﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;

namespace NoteHelper.Model
{
    public static class DataExtensions
    {
        public static IEnumerable<T> ToFullyLoaded<T>(this IQueryable<T> query)
        {
            return query.ToArray().ToList();
        }

        /// <summary>
        /// 将List转换成DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public static DataTable ToDataTable<T>(this IList<T> data, string tableName)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
            var dt = new DataTable(tableName);
            for (int i = 0; i < properties.Count; i++)
            {
                PropertyDescriptor property = properties[i];
                dt.Columns.Add(property.Name, GetBaseType(property.PropertyType));
            }
            object[] values = new object[properties.Count];
            foreach (T item in data)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = properties[i].GetValue(item);
                }
                dt.Rows.Add(values);
            }
            return dt;
        }

        private static Type GetBaseType(Type t)
        {
            var realType = t.IsGenericType ? t.GetGenericArguments()[0] : t;
            return realType;
        }

        public static DataTable ToDataTable<T>(this IList<T> data, string[] needProperties)
        {
            Type t = typeof(T);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));


            var dt = new DataTable();
            foreach (string columnName in needProperties)
            {
                PropertyDescriptor property = properties.Find(columnName, true);
                if (property != null)
                {
                    dt.Columns.Add(columnName, property.PropertyType);
                }
                else
                {
                    dt.Columns.Add(columnName);
                }
            }

            object[] values = new object[needProperties.Length];
            foreach (T item in data)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    PropertyDescriptor property = properties.Find(needProperties[i], true);
                    if (property != null)
                    {
                        values[i] = property.GetValue(item);
                    }
                    else
                    {
                        values[i] = null;
                    }
                }
                dt.Rows.Add(values);
            }
            return dt;
        }

        public static DataSet ToDataSet<T>(this T entity) where T : class
        {
            DataSet ds = new DataSet();
            Type entityType = typeof(T);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
            List<object> values = new List<object>();
            DataTable dt = new DataTable(entityType.Name);
            for (int i = 0; i < properties.Count; i++)
            {
                PropertyDescriptor property = properties[i];
                var value = property.GetValue(entity);
                if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
                {
                    ds.Tables.Add(new DataTable(property.Name));
                    continue;
                }
                if (property.PropertyType.IsGenericType)
                {
                    continue;
                }

                values.Add(value);
                dt.Columns.Add(property.Name, property.PropertyType);
            }
            dt.Rows.Add(values.ToArray());
            ds.Tables.Add(dt);

            return ds;
        }

        public static void FillValueToEntity<T>(this Hashtable ht, T entity) where T : class
        {
            var entityType = entity.GetType();
            var properties = entityType.GetProperties();
            foreach (string key in ht.Keys)
            {
                var property = entityType.GetProperty(key);
                if (property != null)
                {
                    property.SetValue(entity, ht[key]);
                }
            }
        }

        public static void FillEntity<T>(this DataRow row, T entity)
        {
            Type _t = entity.GetType();
            PropertyInfo[] propertys = _t.GetProperties();
            int count = row.Table.Columns.Count;
            for (int i = 0; i < count; i++)
            {
                var propertyName = row.Table.Columns[i].ColumnName;
                PropertyInfo pi = propertys.FirstOrDefault(p => p.Name.ToUpper() == propertyName.ToUpper());
                if (null != pi)
                    pi.SetValue(entity, row[i]);
            }
        }

        public static void UpdateDataRow<T>(this DataRow row, T entity)
        {
            Type _t = entity.GetType();
            PropertyInfo[] propertys = _t.GetProperties();
            int count = row.Table.Columns.Count;
            for (int i = 0; i < count; i++)
            {
                var propertyName = row.Table.Columns[i].ColumnName;
                PropertyInfo pi = propertys.FirstOrDefault(p => p.Name.ToUpper() == propertyName.ToUpper());
                if (null != pi)
                {
                    var value = pi.GetValue(entity);
                    row[i] = value == null ? DBNull.Value : value;
                }
            }
        }
    }
}
